package com.shhm.filter;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.shhm.common.constants.HttpStatus;
import com.shhm.common.entity.admin.SysRoleOperatePerms;
import com.shhm.common.entity.system.SysPassAuth;
import com.shhm.common.mapper.SysRoleOperatePermsMapper;
import com.shhm.common.utils.JwtUtil;
import com.shhm.common.utils.LocalCacheUtil;
import com.shhm.common.utils.RedisUtil;
import com.shhm.common.utils.ResponseUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author JackZ
 * @version 1.0
 * @description: 校验权限拦截器
 * @date 2025/8/1 下午5:12
 */
@Deprecated
public class JwtAuthorization1Filter extends OncePerRequestFilter {
    private final RedisTemplate<String, String> redisTemplate;
    private final String[] pass_uri;
    private final SysRoleOperatePermsMapper roleOperatePermsMapper;
    private final Cache<String, List<SysRoleOperatePerms>> localPermissionsCache;
    private final Cache<String, List<SysPassAuth>> localSysPassAuthCache;
    @Value("${filter.openAuthorization}")
    private boolean openFilter;

    public JwtAuthorization1Filter(
            RedisTemplate<String, String> redisTemplate,
            String[] pass_uri,
            SysRoleOperatePermsMapper roleOperatePermsMapper,
            Cache<String, List<SysRoleOperatePerms>> localPermissionsCache,
            Cache<String, List<SysPassAuth>> localSysPassAuthCache
            ) {
        this.redisTemplate = redisTemplate;
        this.pass_uri = pass_uri;
        this.roleOperatePermsMapper=roleOperatePermsMapper;
        this.localPermissionsCache = localPermissionsCache;
        this.localSysPassAuthCache = localSysPassAuthCache;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        long start = System.currentTimeMillis();
        String uri = request.getRequestURI();
        for (String puri : pass_uri) {
            if (uri.contains(puri)){
                filterChain.doFilter(request, response);
                return;
            }
        }

//        提取数据
        String authHeader = request.getHeader("Authorization");
        if (Objects.isNull(authHeader) || !authHeader.startsWith("Bearer ")){
            ResponseUtil.sendErrorResponse(response, HttpStatus.FORBIDDEN, "您未执行登录操作");
        }
        String method = request.getMethod();
        String operateStr = getOperateStr(method);
        String token = authHeader.substring(7);
        List<String> roles = JwtUtil.getRoleFromToken(token);

        //        处理当前用户角色列表
        Set<String> roleKeys = roles.stream()
                .map(role -> role.startsWith("ROLE_") ? role.substring(5) : role)
                .collect(Collectors.toSet());

        // 4. 检查权限
        if (checkPermInLocalCache(roleKeys, uri, operateStr,method)) {
            filterChain.doFilter(request, response);
            System.out.println("JwtAuthorizationFilter.java-Line-78:本地缓存命中！");
        }else{
            try{
                if (checkPermInRedis(roleKeys, uri, operateStr,method)) {
                    filterChain.doFilter(request, response);
                    System.out.println("JwtAuthorizationFilter.java-Line-82:Redis缓存命中！");
                }
                else ResponseUtil.sendErrorResponse(response, HttpStatus.FORBIDDEN, "您无权进行此操作");
            }catch (Exception e){
                System.out.println("JwtAuthorizationFilter.java-Line-91:Redis缓存连接异常，降级到数据库操作！");
                if (checkPermInDataBase(roleKeys, uri, operateStr,method)) filterChain.doFilter(request, response);
                else ResponseUtil.sendErrorResponse(response, HttpStatus.FORBIDDEN, "您无权进行此操作");
            }

        }
        System.out.println("JwtAuthorizationFilter.java-Line-88:执行时间为："+(System.currentTimeMillis()-start));
    }

    private boolean checkPermInDataBase(Set<String> roles, String uri, String operateStr,String method){
        if (roles == null || roles.isEmpty() || uri == null || operateStr == null) {
            return false;
        }

        LambdaQueryWrapper<SysRoleOperatePerms> query = new LambdaQueryWrapper<SysRoleOperatePerms>()
                .select(SysRoleOperatePerms::getOperateStr)
                .in(SysRoleOperatePerms::getRoleKey, roles)
                .eq(SysRoleOperatePerms::getRequestUri, uri);

        SysRoleOperatePerms result = roleOperatePermsMapper.selectOne(query);

        if (result != null) {
            return hasAccess(result.getOperateStr(), operateStr);
        }

        if ("POST".equalsIgnoreCase(method) && uri.endsWith("/search")) {
            String baseUri = uri.substring(0, uri.length() - "/search".length());
            query = new LambdaQueryWrapper<SysRoleOperatePerms>()
                    .select(SysRoleOperatePerms::getOperateStr)
                    .in(SysRoleOperatePerms::getRoleKey, roles)
                    .eq(SysRoleOperatePerms::getRequestUri, baseUri);

            result = roleOperatePermsMapper.selectOne(query);
            return result != null && hasAccess(result.getOperateStr(), "l");
        }

        return false;
    }

    @Deprecated
    private boolean checkPermInLocalCache1(Set<String> roles, String uri, String operateStr,String method){
        boolean isPass=false;
        for (String role : roles) {
            List<SysRoleOperatePerms> perms = localPermissionsCache.getIfPresent(LocalCacheUtil.CACHE_PERMS_KEY_PREFIX + role);
            if (perms == null || perms.isEmpty()) {
                continue;
            }
            for (SysRoleOperatePerms perm : perms) {
                String permUri = perm.getRequestUri();
                if (uri.equals(permUri) || uri.startsWith(permUri + "/") || uri.startsWith(permUri + "?")) {
                    return hasAccess(perm.getOperateStr(), operateStr);
                }
                else if ("POST".equals(method)
                        && (permUri + "/search").equals(uri)
                        && hasAccess(perm.getOperateStr(), "l")) {
                    return true;
                }
            }
        }
        return isPass;
    }
    private boolean checkPermInLocalCache(Set<String> roles, String uri, String operateStr, String method) {
        for (String role : roles) {
            List<SysRoleOperatePerms> perms = localPermissionsCache.getIfPresent(LocalCacheUtil.CACHE_PERMS_KEY_PREFIX + role);
            if (checkPermission(perms, uri, operateStr, method)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 检查是否拥有某项操作权限
     */
    private boolean hasAccess(String permOperateStr, String requiredOp) {
        if (permOperateStr == null || requiredOp == null) return false;
        return "*".equals(permOperateStr) || permOperateStr.contains(requiredOp);
    }

    // 从Redis缓存中检查权限
    @Deprecated
    private boolean checkPermInRedis1(Set<String> roles, String uri, String operateStr,String method) {
        // 批量获取权限配置
        Map<String, List<SysRoleOperatePerms>> permissions = new HashMap<>();
        for (String role : roles) {
            String key = RedisUtil.REDIS_OPERATE_PERMS_KEY + role;
            String json = redisTemplate.opsForValue().get(key);
            if (json != null && !json.isEmpty()) {
                List<SysRoleOperatePerms> perms = JSON.parseArray(json, SysRoleOperatePerms.class);
                permissions.put(role, perms);
            }
        }
        return hasPermission(permissions, uri,  operateStr, method);
//        for (List<SysRoleOperatePerms> permList : permissions.values()) {
//            for (SysRoleOperatePerms perm : permList) {
//                if (perm.getRequestUri().equals(uri)) {
//                    // 匹配到URI后，检查是否包含操作方法
//                    if (perm.getOperateStr().contains(operateStr)
//                            ||perm.getOperateStr().equals("*")) {
//                        return true;
//                    }
//                    break; // 同一URI只需匹配一次
//                }else if ((perm.getRequestUri()+"/search").equals(uri)&&method.equals("POST")&&(perm.getOperateStr().contains("l")||perm.getOperateStr().contains("*"))) return true;
//            }
//        }
//        return false;
    }

    private boolean checkPermInRedis(Set<String> roles, String uri, String operateStr, String method) {
    Map<String, List<SysRoleOperatePerms>> permissions = new HashMap<>();
    for (String role : roles) {
        String key = RedisUtil.REDIS_OPERATE_PERMS_KEY + role;
        String json = redisTemplate.opsForValue().get(key);
        if (json != null && !json.isEmpty()) {
            List<SysRoleOperatePerms> perms = JSON.parseArray(json, SysRoleOperatePerms.class);
            permissions.put(role, perms);
        }
    }

    for (List<SysRoleOperatePerms> perms : permissions.values()) {
        if (checkPermission(perms, uri, operateStr, method)) {
            return true;
        }
    }
    return false;
}


    /**
     * 通用权限检查方法
     */
    private boolean checkPermission(List<SysRoleOperatePerms> perms, String uri, String operateStr, String method) {
        if (perms == null || perms.isEmpty()) {
            return false;
        }
        for (SysRoleOperatePerms perm : perms) {
            String permUri = perm.getRequestUri();
            String matchMethod = perm.getMatchMethod() != null ? perm.getMatchMethod() : "exact";

            boolean isMatch = switch (matchMethod.toLowerCase()) {
                case "prefix" ->
                        uri.equals(permUri) ||
                                uri.startsWith(permUri + "/") && uri.length() > permUri.length() ||
                                uri.startsWith(permUri + "?") && uri.length() > permUri.length() ||
                                ("POST".equals(method) && (permUri + "/search").equals(uri));
                default ->
                        uri.equals(permUri);
            };

            if (isMatch && hasAccess(perm.getOperateStr(), operateStr)) {
                return true;
            }
        }
        return false;
    }

    /**
     *  双重检查：先匹配URI，在同一URI中再匹配操作
     * @param permissions
     * @param uri
     * @param operateStr
     * @param method
     * @return boolean
     */
    private boolean hasPermission(
            Map<String, List<SysRoleOperatePerms>> permissions,
            String uri,
            String operateStr,
            String method){
        for (List<SysRoleOperatePerms> permList : permissions.values()) {
            for (SysRoleOperatePerms perm : permList) {
                if (perm.getRequestUri().equals(uri)) {
                    // 匹配到URI后，检查是否包含操作方法
                    if (perm.getOperateStr().contains(operateStr)
                            ||perm.getOperateStr().equals("*")) {
                        return true;
                    }
                    break; // 同一URI只需匹配一次
                }else if ((perm.getRequestUri()+"/search").equals(uri)&&method.equals("POST")&&(perm.getOperateStr().contains("l")||perm.getOperateStr().contains("*"))) return true;
            }
        }
        return false;
    }


//    获取对应的权限字符
    private String getOperateStr(String method){
        String res="";
        if (method.equals("GET")) res= "l";
        else if (method.equals("POST")) res= "a";
        else if (method.equals("DELETE")) res= "d";
        else if (method.equals("PUT")) res= "u";
        else res="unknown";
        return res;
    }
}
